
namespace Behemoth.SharePoint.Data {

    using System;
    using System.ComponentModel;
    using System.Collections.Generic;
    using System.IO;
    using System.Text;
    using System.Xml.Serialization;
    using System.Reflection;

    using System.Web.UI;
    using System.Web.UI.WebControls;
    using Microsoft.SharePoint;
    using Microsoft.SharePoint.WebControls;

	public partial class DataSourceControlProperties {

		private IDataSource controlInstance = null;

		public static DataSourceControlProperties GetPropertiesFromFile( string filePath ) {
			DataSourceControlProperties dsp = null;
			using (FileStream fs = new FileStream( filePath, FileMode.Open )) {
				try {
					XmlSerializer ser = new XmlSerializer( typeof( DataSourceControlProperties ) );
					object o = ser.Deserialize( fs );
					dsp = o as DataSourceControlProperties;
				} finally {
					fs.Close();
				}
			}
			return dsp;
		}


		private IDataSource CreateClassInstance( string assemblyName, string typeName ) {
			IDataSource controlInstance = null;
			Assembly asm = Assembly.Load( assemblyName );
			if (asm == null)
				throw new Exception( string.Format( "Assembly.Load(...) returned null. Ensure that the AssemblyNane attribute is the correct name and format (including the public key token). Value was '{0}'.", this.AssemblyName, this.TypeName ) );
			object o = asm.CreateInstance( typeName, false );
			if (o == null)
				throw new Exception( string.Format( "CreateInstance(...) returned null. Ensure that the TypeName attribute is the correct full name for the type (including namespace). Value was '{1}'.", this.AssemblyName, this.TypeName ) );
			try {
				controlInstance = o as IDataSource; // WebControl;
				if (controlInstance == null)
					throw new Exception( string.Format( "Specified instance was created successfully, but is not decended from 'System.Web.UI.DataSourceControl'. Assembly='{0}' Type='{1}'", this.AssemblyName, this.TypeName ) );
			} catch (Exception ex) {
				string msg = string.Format( "Error while attempting to create instance of data source control type '{0}' from assembly '{1}'. This exception was: {2}",
					this.AssemblyName,
					this.TypeName,
					ex.Message );
				throw new Exception( msg, ex );
			}
			return controlInstance;
		}

		public IDataSource CreateControl() {
			this.controlInstance = CreateClassInstance( this.AssemblyName, this.TypeName );
			// we got past creating the object, now lets populate its values
			if (controlInstance.GetType() == typeof( SPDataSource )) {
				SPDataSource typedControl = controlInstance as SPDataSource;
				typedControl.DataSourceMode = this.SharePointProperties.DataSourceMode; // Enum.Parse(typeof(SPDataSourceMode), this.SharePointProperties.DataSourceMode, false );
				typedControl.IncludeHidden = this.SharePointProperties.IncludeHidden;
				/*
				// parse the list name or guid
				Guid listGuid = Guid.Empty;
				try {
					listGuid = new Guid(this.SharePointProperties.ListNameOrId);
				} catch {
					// assume it is a list name
					listGuid = Guid.Empty;
				}
				// get the list object from SharePoint - only works for the current web application
				SPList list = null; //SPContext context = SPContext.Current;
				using (SPSite site = new SPSite( this.SharePointProperties.WebUrl )) {
					using (SPWeb web = site.OpenWeb()) {
						if (listGuid != Guid.Empty) {
							list = web.Lists[listGuid];
						} else {
							list = web.Lists[this.SharePointProperties.ListNameOrId];
						}
						// TODO is this going to be okay considering that the SPSite and SPWeb go out of scope???
						// maybe we can destroy the objects later as part of an unload event for the data source control
						typedControl.List = list; 
					}
				}
				*/
				typedControl.Scope = this.SharePointProperties.Scope; // Enum.Parse( typeof( SPViewScope ), this.SharePointProperties.Scope, false );
				typedControl.UseInternalName = this.SharePointProperties.UseInternalName;

				typedControl.SelectCommand = this.SelectCommand;
				foreach (Parameter p in this.SelectParameters)
					typedControl.SelectParameters.Add(p);
				typedControl.InsertCommand = this.InsertCommand;
				foreach (Parameter p in this.InsertParameters)
					typedControl.InsertParameters.Add(p);
				typedControl.UpdateCommand = this.UpdateCommand;
				foreach (Parameter p in this.UpdateParameters)
					typedControl.UpdateParameters.Add(p);
				typedControl.DeleteCommand = this.DeleteCommand;
				foreach (Parameter p in this.DeleteParameters)
					typedControl.DeleteParameters.Add(p);

				typedControl.ID = "SpDataSourceControl_Dynamic_" + this.Name;
			} else if (controlInstance.GetType() == typeof( SPSqlDataSource )) {
				throw new NotImplementedException( string.Format( "The specified type '{0}' is not yet implemented.", this.TypeName ) );
			} else if (controlInstance.GetType() == typeof( SPWorkflowDataSource )) {
				throw new NotImplementedException( string.Format( "The specified type '{0}' is not yet implemented.", this.TypeName ) );
			} else if (controlInstance.GetType() == typeof( SPXmlDataSource )) {
				throw new NotImplementedException( string.Format( "The specified type '{0}' is not yet implemented.", this.TypeName ) );
			} else if (controlInstance.GetType() == typeof( XmlDataSource )) {
				XmlDataSource typedControl = (XmlDataSource)controlInstance;
				typedControl.DataFile = this.XmlProperties.DataFile;
				typedControl.TransformFile = this.XmlProperties.TransformFile;
				typedControl.XPath = this.XmlProperties.XPath;
				// TODO extend this to support more types of data
				//typedControl.Data = this.XmlProperties.Data;
				//typedControl.Transform = this.XmlProperties.Transform;
				//typedControl.TransformArgumentList = this.XmlProperties.SelectParameters;
			} else if (controlInstance.GetType() == typeof( XmlUrlDataSource )) {

				/*
				XmlUrlDataSource typedControl = (XmlUrlDataSource)controlInstance;
				if (this.Authentication != null) {
					if (!string.IsNullOrEmpty( this.Authentication.AuthType ))
						typedControl.AuthType = this.Authentication.AuthType;
					if (!string.IsNullOrEmpty( this.Authentication.AuthUserName ))
						typedControl.AuthUserName = this.Authentication.AuthUserName;
					if (!string.IsNullOrEmpty( this.Authentication.AuthPassword ))
						typedControl.AuthPassword = this.Authentication.AuthPassword;
				}
				// TODO implement the passing of typedControl.DataFileParameters
				typedControl.HttpMethod = this.WebProperties.HttpMethod;
				// TODO typedControl.XPath = this.XmlProperties.XPath;

				typedControl.SelectCommand = this.SelectCommand;
				foreach (Parameter p in this.SelectParameters)
					typedControl.SelectParameters.Add( p );
				typedControl.InsertCommand = this.InsertCommand;
				foreach (Parameter p in this.InsertParameters)
					typedControl.InsertParameters.Add( p );
				typedControl.UpdateCommand = this.UpdateCommand;
				foreach (Parameter p in this.UpdateParameters)
					typedControl.UpdateParameters.Add( p );
				typedControl.DeleteCommand = this.DeleteCommand;
				foreach (Parameter p in this.DeleteParameters)
					typedControl.DeleteParameters.Add( p );

				typedControl.ID = "XmlUrlDataSource_Dynamic_" + this.Name;
				*/

				throw new NotImplementedException( string.Format( "The specified type '{0}' is not yet implemented.", this.TypeName ) );

			} else {
				throw new NotImplementedException( string.Format( "The specified type '{0}' is not yet implemented.", this.TypeName ) );
			}
			return controlInstance;
		}

	} // class
} // namespace
